package model;

import Enums.Notifier;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.Serializable;
import java.util.Observable;

/**
 * Model-Klasse des Originalbildes
 */
public class Model_Image_Original extends Observable implements Serializable {

    // die maske dient dem gewichten der bildbereiche, werte gößer in der maske heißt dieser bereich wurde stärker gewichtet
    private transient BufferedImage image_original, maske;
    private transient Image imgResized;
    private int[][] grayValues, grayValuesMaske;

    /**
     * fuellt das zweidimensionale Array grayValues mit Inhalt, d.h. mit dem
     * Grauwert des Originalbildes bei dem entsprechenden Pixel
     */
    private void create_grayValuematrix() {
        grayValues = new int[this.getWidth()][this.getHeight()];

        for (int i = 0; i < this.getWidth(); i++) {
            for (int j = 0; j < this.getHeight(); j++) {
                grayValues[i][j] = getGray(image_original.getRGB(i, j));
            }
        }
    }

    /**
     * gibt den Grauwert eines rgb-Pixels zurueck
     * @param rgb
     * @return
     */
    private int getGray(int rgb) {
        int gray = rgb & 0xFF;
        return gray;
    }

    /**
     * gibt das Grauwerte-Array des Originalbildes zurueck
     * @return
     */
    public int[][] getGrayValues() {
        if (this.grayValues == null) {
            create_grayValuematrix();
        }
        return this.grayValues;
    }

    /**
     * gibt das Grauwerte-Array der Gewichtungmaske zurueck
     * @return
     */
    public int[][] getGrayValuesMaske() {
        if (grayValuesMaske == null) {
            create_grayValuematrixMaske();
        }
        return this.grayValuesMaske;
    }

    public BufferedImage getImage_original() {
        return image_original;
    }

    /**
     * gibt das Originalbild skaliert mit richtigen Seitenverhaeltnissen
     * es wird eine temporaere kopie des bildes erstellt, falls ein erneuter aufruf
     * kommt, wird die kopie zurueckgegeben
     * @param width die Breite des skalierten Bildes
     * @param height Die Hoehe des skalierten Bildes
     * @return
     */
    public Image getImage_resized(int width, int height) {
        if (imgResized == null) {
            imgResized = image_original;
        }
        //if (image_original != null)// || (imgResized.getWidth(null) > width || imgResized.getHeight(null) > height))

        if (imgResized.getWidth(null) != width /*| imgResized.getWidth(null) < width*/) {
            imgResized = image_original.getScaledInstance(width, -1, Image.SCALE_SMOOTH);
        }
        if (imgResized.getHeight(null) > height) {
            imgResized = image_original.getScaledInstance(-1, height, Image.SCALE_SMOOTH);
        }

        return this.imgResized;
    }

    public void setImage_original(BufferedImage image_orig) throws Exception {
        //konvertiere farbiges Bild in schwarz-weisses Bild
        try {
        ColorConvertOp grayScaleConversionOp = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        image_original = grayScaleConversionOp.filter(image_orig, null);
        Image scaledImage = image_original;
        if(scaledImage.getWidth(null) > 200 ){
            scaledImage = scaledImage.getScaledInstance(200, -1, Image.SCALE_SMOOTH);
        }

        if(scaledImage.getHeight(null) > 200){
            scaledImage = scaledImage.getScaledInstance(-1, 200, Image.SCALE_SMOOTH);
        }
//        System.out.println("scaled: " + scaledImage.getWidth(null)+" "+scaledImage.getHeight(null));

          this.image_original = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), BufferedImage.TYPE_BYTE_GRAY);
          this.image_original.getGraphics().drawImage(scaledImage, 0, 0, null);
          maske = new BufferedImage(image_original.getWidth(), image_original.getHeight(), image_original.getType());
//        System.out.println("maske: " + maske.getWidth()+" "+maske.getHeight());
        this.imgResized = null;
        this.grayValues = null;
        this.grayValuesMaske = null;

        setChanged();
        notifyObservers(Notifier.OriginalImage);
        }
        catch(Exception e){
            throw new Exception("Bild ist beschädigt");
        }
    }

    public int getHeight() {
        return this.image_original.getHeight();
    }

    public int getWidth() {
        return this.image_original.getWidth();
    }

    public BufferedImage getMaske() {
        return this.maske;
    }

    public void setMaske(BufferedImage maske){
        this.maske = maske;
    }

    /**
     * erstellt das Grauwerte-Array der Gewichtungmaske
     */
    public void create_grayValuematrixMaske() {
        grayValuesMaske = new int[this.maske.getWidth()][this.maske.getHeight()];

        for (int i = 0; i < this.getWidth(); i++) {
            for (int j = 0; j < this.getHeight(); j++) {
                grayValuesMaske[i][j] = getGray(maske.getRGB(i, j));
            }
        }
    }
}
